Amazon Aurora DSQLの主キーで気をつけるべきこと
Active-Activeな分散データベースであるAurora DSQLはリレーショナルモデルを採用しています。
Getting startedドキュメントにあるテーブル作成例を確認すると、主キーとして UUID が使われています。
Create an invoice table that uses an automatically generated UUID as the primary key.
CREATE TABLE example.invoice(
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
created timestamp,
purchaser int,amount float);
Aurora DSQLの主キーのドキュメントには、短い文章の中に伝統的なRDBとの違いについての多くの情報が詰め込まれています。
実務観点では、以下を意識しましょう。
- 主キーが分散データの肝
- 主キーにはまずUUIDを考えるべし
- 主キーの指定は必須ではない
- 主キーは後から変更できない
- シリアルには対応していない
- 主キーのアクセスはCLUSTERとINCLUDEの合せ技
主キーが分散データの肝
Aurora DSQLでは、主キーがパーティショニングやスケーリングや同時実行制御に使われます。そのため、主キーの選択は非常に重要です。
Aurora DSQL uses this main concept to organize distributed data management. Aurora DSQL uses the primary key to construct a cluster-wide unique key that's assigned to each row in each table or index. Aurora DSQL uses this key to automatically partition storage. This partition key plays a central role in Aurora DSQL automatic scaling and concurrency control mechanisms.
https://docs.aws.amazon.com/aurora-dsql/latest/userguide/working-with-primary-keys.html
主キーにはまずUUIDを考えるべし
トランザクションデータのように更新が多いテーブルには、UUIDのようなランダムな値を利用しましょう。シリアルのような連番("monotonically increasing integers" DSQLはシリアルを対応しません)を使うと、書き込みのパーティションが偏り、性能低下を招きます。
For tables with high write volumes, avoid using monotonically increasing integers as primary keys, which can lead to weaker performance. Randomness in primary keys ensures even distribution of new writes across storage partitions. Instead, using monotonically increasing integers as primary keys can lead to all new inserts being directed to a single partition, which creates a bottleneck.
https://docs.aws.amazon.com/aurora-dsql/latest/userguide/working-with-primary-keys.html
postgres=> create table foo(id uuid PRIMARY KEY DEFAULT gen_random_uuid(), name text);
CREATE TABLE
postgres=> insert into foo(name) values('a'), ('b');
INSERT 0 2
postgres=> select * from foo;
id | name
--------------------------------------+------
04d288b0-870c-44bf-8dd6-729e465bd664 | a
7cf7b365-008b-423d-9d77-59d062bf76a4 | b
(2 rows)
gen_random_uuid()
関数は UUID v4 の値を返します。
Aurora DSQLはエクステンションに対応していないため、uuid-ossp
モジュールは使えません。
更新の少ないマスタデータのようなテーブルでは、書き込みパフォーマンスがシビアではないので、連番のようなランダムでない値でも構いません。
If your table doesn't change very often or is read-only, you can use an ascending key, even if it is a dense key. Doing so is fine because there you don't need a high level of performance for loading data into the key.
https://docs.aws.amazon.com/aurora-dsql/latest/userguide/working-with-primary-keys.html
主キーの指定は必須ではない
主キーの指定しなくても、テーブルを作れてしまいます。
postgres=> create table foo(id int);
postgres=> \d+ foo
Table "public.foo"
Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description
--------+---------+-----------+----------+---------+---------+-------------+--------------+-------------
id | integer | | | | plain | | |
Access method: btree_table
主キーを指定しない場合、DSQLは暗黙にIDを割り当てますが、大きいテーブルに対して、JOINできなかったり、ルックアップが遅くなる可能性があります。
While Aurora DSQL assigns a synthetic hidden ID if you don't define a primary key, this might not support join operations or fast indexed lookups for larger tables.
https://docs.aws.amazon.com/aurora-dsql/latest/userguide/working-with-primary-keys.html
テーブル作成時には、主キーを明示的に指定しましょう。
主キーは後から変更できない
Aurora DSQLでは主キーを変更したり、後から設定することができません。
後から追加しようとすると、エラーが発生します。
postgres=> create table foo(id int);
CREATE TABLE
postgres=> alter table foo add constraint foo_pkey primary key(id);
ERROR: unsupported ALTER TABLE ADD CONSTRAINT statement
後から削除しようとすると、エラーが発生します。
postgres=> create table foo2(id int primary key);
CREATE TABLE
postgres-> \d foo2
Table "public.foo2"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
id | integer | | not null |
Indexes:
"foo2_pkey" PRIMARY KEY, btree_index (id)
postgres=> alter table foo drop constraint foo2_pkey;
ERROR: unsupported ALTER TABLE DROP CONSTRAINT statement
シリアルには対応していない
"Unsupported PostgreSQL features in Aurora DSQL" にあるように、Aurora DSQLはシーケンスに対応していません。
postgres=> create table bar(id serial primary key);
ERROR: type "serial" does not exist
LINE 1: create table bar(id serial primary key);
postgres=> CREATE SEQUENCE foo;
ERROR: unsupported statement: CreateSeq
主キーのアクセスはCLUSTERとINCLUDEの合せ技
Aurora DSQLでテーブルを作成すると、 Access method
が heap ではなく btree_table となっています。
postgres=> create table foo(id int);
CREATE TABLE
postgres=> \d+ foo
Table "public.foo"
Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description
--------+---------+-----------+----------+---------+---------+-------------+--------------+-------------
id | integer | | | | plain | | |
Access method: btree_table
Aurora DSQLでは、主キーを指定することで、主キーでのアクセスの高速化などでよく使われる クラスター化インデックス の作成のような動きをし、各レコードは主キーでソートされた状態で格納されます。PostgreSQLの CLUSTER
は操作時のみソートされますが、Aurora DSQLではデータ更新を伴ってもこの順序が維持されます。
また、PostgreSQLのCREATE INDEX
ステートメントには INCLUDE
オプションがあり、インデックスキーではないカラムデータも含めることができます。Aurora DSQLはこの機能を応用し、全カラムを INCLUDE
することで、主キーのインデックスアクセスから全カラムデータも取得できるようになっています。
In Aurora DSQL, defining a primary key for your table is similar to the CLUSTER operation in PostgreSQL or a clustered index in other database systems. Aurora DSQL applies an INCLUDE statement that references all columns, which creates a table organized by an index. This structure makes it so that any lookup against an Aurora DSQL primary key can access all column values associated with the key, and the data is always ordered according to the primary key. Unlike the CLUSTER operation, Aurora DSQL always maintains the order of this index-organized table.
Aurora DSQL uses this main concept to organize distributed data management.
https://docs.aws.amazon.com/aurora-dsql/latest/userguide/working-with-primary-keys.html
参考
- What are table access methods, and what is their importance to PostgreSQL?
- Clustered indexes are index-organized tables
- PostgreSQL: Documentation: CLUSTER
- PostgreSQL: Documentation: CREATE INDEX
まとめ
Aurora DSQLの主キーのドキュメントには、重要な概念が行間が広く書かれているように感じました。
新規にシステム構築や既存のRDBなシステムを移行時に、何度も読み返すことになりそうな1ページです。